package com.itheima.ai.RAG;

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.SystemMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.chat.prompt.SystemPromptTemplate;
import org.springframework.ai.document.Document;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;

/**
 * RAG服务：优先从向量库检索内容，再让AI生成回答
 */
@Service
public class RagService {

    // 关键：明确注入自定义的向量库Bean（避免依赖冲突）
    private final VectorStore vectorStore;

    // AI聊天客户端（Ollama的DeepSeek模型）
    private final ChatClient chatClient;

    // 构造函数：用@Qualifier指定向量库Bean名，确保注入正确
    @Autowired
    public RagService(
            @Qualifier("elasticsearchVectorStore") VectorStore vectorStore,
            ChatClient chatClient) {
        this.vectorStore = vectorStore;
        this.chatClient = chatClient;
    }

    /**
     * 处理用户提问：先检索向量库，再生成回答
     *
     * @param userQuestion 用户问题
     * @return AI基于检索结果生成的回答
     */
    public String answerWithRag(String userQuestion) {
        try {
            // 步骤1：从向量库检索与问题相关的文档（前3条最相关的结果，明确指定数量）
            List<Document> relevantDocs = vectorStore.similaritySearch(userQuestion);
            System.out.println("检索到相关文档：" + relevantDocs.size() + "条");

            // 步骤2：拼接上下文（核心修正：用doc.getContent()获取PDF文本）
            StringBuilder context = new StringBuilder();
            for (int i = 0; i < relevantDocs.size(); i++) {
                Document doc = relevantDocs.get(i);
                // 1. 获取PDF文本内容（getContent()是Spring AI Document的标准内容字段）
                String docContent = doc.getFormattedContent();
//                String docContent = doc.getText();
                // 2. 获取PDF页码（从metadata中提取，增强上下文可读性）
                String pageNum = doc.getMetadata().get("pageNumber").toString();
                // 3. 拼接单条文档上下文（带页码标识，方便定位来源）
                context.append("【文档").append(i + 1).append("（页码：").append(pageNum).append("）】\n")
                        .append(docContent).append("\n\n");
            }

            // 步骤3：构建提示词（增加空上下文判断，避免AI无意义回答）
            String systemPrompt = """
                    你是一个知识问答助手，必须严格基于以下上下文回答用户问题：
                    1. 优先使用上下文里的信息，不编造外部内容；
                    2. 如果上下文为空或没有相关信息，直接回复"没有找到相关信息"；
                    3. 回答时要条理清晰，可引用上下文的文档编号（如"根据文档1"）。
                    
                    上下文：
                    {context}
                    """;

            // 填充上下文（若上下文为空，主动标记，避免AI误解）
            String filledContext = context.length() == 0 ? "无相关文档" : context.toString();
            SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate(systemPrompt);
            String filledSystemPrompt = systemPromptTemplate.render(Map.of("context", filledContext));

            // 构建消息列表（符合ChatClient的标准消息格式）
            List<Message> messages = List.of(
                    new SystemMessage(filledSystemPrompt),
                    new UserMessage(userQuestion)
            );
            Prompt prompt = new Prompt(messages);

            // 步骤4：调用AI生成回答（增加异常捕获，避免单次检索失败影响整体服务）
            String response = chatClient
                    .prompt(prompt)
                    .call()
                    .content();

            return response;
        } catch (Exception e) {
            // 打印检索/生成异常日志，方便排查问题
            System.err.println("RAG处理失败！问题：" + userQuestion + "，原因：" + e.getMessage());
            e.printStackTrace();
            return "检索服务暂时异常，请稍后再试";
        }
    }
}